package pogvue.datamodel;


import java.util.*;
import java.awt.event.*;
import pogvue.gui.hub.*;
import pogvue.gui.event.*;
import pogvue.gui.*;

public class SequenceFragment extends Sequence implements ActionListener {
    Vector frags;
    String type;

    Vector threads = null;

    Controller c;
    AlignViewport av;

  String org;

    public SequenceFragment(String name, String sequence, int start, int end) {
	super(name,sequence,start,end);

	// Start end coords are in global chromosome coords

	this.length = end-start+1;

	frags = new Vector();

    }

    public void setAlignViewport(AlignViewport av) {
	this.av = av;
	if (av.getController() != null) {
	  setController(av.getController());
	}
    }

    public void setController(Controller c) {
	this.c = c;

    }

  public void setOrg(String org) {
    this.org = org;
  }
    public void getSequenceRegion(int tmpstart, int tmpend) {
      //System.out.println("Getting region " + tmpstart + " " + tmpend);
        
      // Check all the regions to see if we're covered

      Fragment found = null;
      //System.out.println("Frags size " + frags.size());
      for (int i = 0; i < frags.size(); i++) {
          Fragment f = (Fragment)frags.elementAt(i);
	  //System.out.println("Start " + f.getStart() + " " + f.getEnd() + " " + tmpstart + " " + tmpend);
	  if (f.getStart() <= tmpstart &&
	      f.getEnd()   >= tmpend) {

	      found = (Fragment)frags.elementAt(i);
	  }
      }


      // If not generate a list of Fragments we need to get
      Vector newfrags = findFrags(tmpstart,tmpend);

      // Fetch fragments
      for (int i = 0; i < newfrags.size(); i++) {
	  Fragment f = (Fragment)newfrags.elementAt(i);
	  //System.out.println("New frag " + f.getStart() + " " + f.getEnd());
      
	  fetchFragment((Fragment)newfrags.elementAt(i));
	  frags.addElement(f);
	  //System.out.println("Frags size " + frags.size());
      }

    }

  public void fetchFragment(Fragment f) {
    //System.out.println("Fetching fragment " + f.getStart() + " " + f.getEnd() + " " + f.getFeatures() +  " " + org);
    
    GetRegionThread r = new GetRegionThread(getName(),String.valueOf(f.getStart()),String.valueOf(f.getEnd()),this,f,org);
    r.setFragment(f);
    r.start();

    if (threads == null) {
	threads = new Vector();
    }

    threads.addElement(r);
  }

    public Vector findFrags(int start, int end) {

	// If we have no frags then we just create a fresh one
	Vector newFrags = new Vector();

	if (frags.size() == 0) {
	    Fragment f = new Fragment(start,end,"");
	    newFrags.addElement(f);
	    //System.out.println("Initializing frags");
	    return newFrags;
	}
	
	// Sort the fragments by start coord (none should overlap)

	Collections.sort(frags,new FragmentStartComparer());

	// Check whether the gaps overlap the region
	
	Fragment prev = null;

	// Check initial gap

	for (int i = 0; i < frags.size(); i++) {
	    Fragment f1 = (Fragment)frags.elementAt(i);
	    //Initial gap
	    if (i == 0) {
		int tmpstart = 1;
		int tmpend   = f1.getStart()-1;

		if (!(tmpstart > end ||
		      tmpend   < start)) {

		    if (start < tmpstart) {
			start = tmpstart;
		    }
		    if (end > tmpend) {
			end  = tmpend;
		    }

		    Fragment f = new Fragment(start,end,"");
		    newFrags.addElement(f);
		    //System.out.println("Adding start gap " + start + " " + end);
		}
	    }
	    // Middle gaps
	    if (i > 0) {

		int tmpstart = prev.getEnd()+1;
		int tmpend   = ((Fragment)frags.elementAt(i)).getStart()-1;
		
		//System.out.println("tmpstart/end " + tmpstart + " " + tmpend);

		if(tmpend >= tmpstart) {
		    if (!(tmpstart > end ||
			  tmpend   < start)) {
			
			if (start < tmpstart) {
			    start = tmpstart;
			}
			if (end > tmpend) {
			    end = tmpend;
			}
			Fragment f = new Fragment(start,end,"");
			newFrags.addElement(f);
			//System.out.println("Adding middle gap " + start + " " + end);
		    }
		}
	    }

	    // End gap

	    if (i == frags.size()-1) {
		int tmpstart = f1.getEnd()+1;
		int tmpend   = getEnd();

		if (!(tmpstart > end ||
		      tmpend   < start)) {

		    if (start < tmpstart) {
			start = tmpstart;
		    }
		    if (end > tmpend) {
			end = tmpend;
		    }
			
		    Fragment f = new Fragment(start,end,"");
		    newFrags.addElement(f);
		    //System.out.println("Adding end gap " + start + " " + end);
		}

	    }

	    prev = (Fragment)frags.elementAt(i);
	}

	//return the new frags

	return newFrags;
    }

    public void printFrags() {
      System.out.println("\n*****");

	for (int i = 0; i < frags.size(); i++) {
	    Fragment f = (Fragment)frags.elementAt(i);

	    System.out.println(" - " + f.getStart() + " " + f.getEnd() + " " + (f.getEnd()-f.getStart()+1));
	}
	System.out.println("\n*****\n");
    }

  public String getSubString(int i, int j) {
    StringBuffer s = new StringBuffer();

    while (i <= j) {
      s.append(getCharAt(i));
      i++;
    }

    return s.toString();
  }
    // The method that gets called for Sequences is getCharAt (also getSequence().substring - but this
    // should be changed

  public String getSequence(int start,int end) {
    StringBuffer str = new StringBuffer();

    for (int i = start; i <= end; i++) {
      str.append(getCharAt(i));
    }

    return str.toString();
  }
    public char getCharAt_dummy(int coord) {
      return 'A';
    }
    public char getCharAt(int coord) {
	char c = 'A';
       
        // coord is in the local coordinate frame i.e. 0-N 
        // Fragments are in global coordinate frame

	// If already overlaps then don't fetch more
	boolean found = false;

	for (int i = 0; i < frags.size(); i++) {
	  Fragment f = (Fragment)frags.elementAt(i);

           //System.out.println(" FRAGGIW " + coord + " " + f.getStart() + " " + f.getEnd() + " " + f.getStr().length());

	  if (!(coord + getStart()-1 > f.getEnd() ||
		coord + getStart()-1  < f.getStart())) {
	    if (f.getStr().length() > 0) {
	      // put in sequence 
	      c = f.getStr().charAt(coord - f.getStart()+getStart());
	      //System.out.println("Got char " + c);
	    } else {
	      //System.out.println("Got pending feature ***************");
	      c = 'C';
	    }
	    //   System.out.println("Found overlap %%%%%");
	    found = true;
	  }
	}
	if (found == true) {
	    // return something here
	  return c;
	}
	

	// Fetch a biggish piece here how big for sequences - db fetch is optimized for 200kb
        // network download time will be the decider here.

	int tmpstart = coord - 100000 + getStart();
        
	if (tmpstart < 1) {tmpstart = 1;}

	int tmpend   = coord + 100000 + getStart();
	if (tmpend > getEnd()) {tmpend = getEnd();}

	//System.out.println("\n\nGetting new sequence region " + tmpstart + " " + tmpend);
	
	getSequenceRegion(tmpstart,tmpend);

	//printFrags();

	for (int i = 0; i < frags.size(); i++) {
	    Fragment f = (Fragment)frags.elementAt(i);
	    
	    if (!(f.getStart() > coord + getStart()-1 ||
		  f.getEnd()   < coord + getStart()-1)) {
		if (f.getStr() != null && f.getStr().length() > coord) {
		    // sequence is here
                    //System.out.println("Getting char " + coord + " " + f.getStr());
                    c = f.getStr().charAt(coord - f.getStart() + getStart());
		} else {
		  // System.out.println("Got pending feature ***************");
		  // put in dummy sequence
                   c = 'T';
                }
	    }
	}

	return c;
    }

    public void actionPerformed(ActionEvent e) {
	if (e.getActionCommand().equals("Done")) {

	    for (int ii = 0; ii < threads.size(); ii++) {
	      GetRegionThread t = (GetRegionThread)threads.elementAt(ii);
	      Fragment         f = t.getFragment();

	      if (e.getSource() == t) {
		SequenceI[] seqs = t.getOutput();
		//System.out.println("Fragment " + f  + " [" + seqs +"]");	    
		// This should be the org string - couldn't be bothered here.'
		f.setStr(seqs[1].getSequence());
		
		threads.removeElement(t);
		
		//System.out.println("Firing event " + c);
		if (c != null) {
		  
		  
		  
		  if (!(av.getStartRes() > t.getFragment().getEnd() - getStart()||
			av.getEndRes()   < t.getFragment().getStart() - getStart())) {

		    //System.out.println("Redrawing screen");
		    // Only need to redraw if the features are on the screen!!!
		    // Doesn't explain the top panel though!
		    //c.handleAlignViewportEvent(new AlignViewportEvent(this,av,AlignViewportEvent.COLOURING));
		  }
		}
	      }
	    }
	    
	}
    }
  
}











